package com.erli.exchange.core.util;


import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;

import org.springframework.util.CollectionUtils;

public final class JSRValidation {

    private JSRValidation() {
    }

    private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();


    /**
     * jsr校验
     *
     * @param obj 为null时会抛异常
     * @param <T>
     */
    public static <T> void checkEntityArgument(T obj) {
        ValidationResult validationResult = validateEntity(obj);
        if (validationResult.hasErrors) {
            throw new IllegalArgumentException(format(validationResult));
        }
    }

    /**
     * 格式化错误信息
     *
     * @param validationResult
     * @return
     */
    private static String format(ValidationResult validationResult) {
        StringJoiner stringJoiner = new StringJoiner("\n");
        Map<String, String> map = validationResult.getErrorMsg();
        map.values().forEach(stringJoiner::add);
        return stringJoiner.toString();
    }


    /**
     * 校验对象
     *
     * @param obj
     * @return
     */
    public static <T> ValidationResult validateEntity(T obj) {
        return validateEntity(obj, Default.class);
    }
    
    /**
     * 校验对象
     * @param obj        	待校验对象
     * @param groups        待校验的组
     */
    public static <T> ValidationResult validateEntity(T obj, Class<?>... groups) {
    	Set<ConstraintViolation<Object>> set = null;
    	if (groups == null) {
    		set = validator.validate(obj, Default.class);
    	} else {
    		set = validator.validate(obj, groups);
    	}
        return fittingResult(set);
    }

    /**
     * 校验属性
     *
     * @param obj
     * @param propertyName
     * @return
     */
    private static <T> ValidationResult validateProperty(T obj, String propertyName) {
        Set<ConstraintViolation<T>> set = validator.validateProperty(obj, propertyName, Default.class);
        return fittingResult(set);
    }

    private static <T> ValidationResult fittingResult(Set<ConstraintViolation<T>> set) {
        ValidationResult result = new ValidationResult();
        if (!CollectionUtils.isEmpty(set)) {
            result.setHasErrors(true);
            Map<String, String> errorMsg = new HashMap<String, String>();
            set.forEach(cv -> errorMsg.put(cv.getPropertyPath().toString(), cv.getMessage()));
            result.setErrorMsg(errorMsg);
        }
        return result;
    }

    /**
     * 数据校验结果
     */
    public final static class ValidationResult {

        private boolean hasErrors;

        Map<String, String> errorMsg;

        public boolean isHasErrors() {
            return hasErrors;
        }

        public void setHasErrors(boolean hasErrors) {
            this.hasErrors = hasErrors;
        }

        public Map<String, String> getErrorMsg() {
            return errorMsg;
        }

        public void setErrorMsg(Map<String, String> errorMsg) {
            this.errorMsg = errorMsg;
        }

        @Override
        public String toString() {
            return "ValidationResult{" +
                    "hasErrors=" + hasErrors +
                    ", errorMsg=" + errorMsg +
                    '}';
        }
    }

}

